package org.marverse.scripting

import ScriptingUtil._

sealed trait VariableDeclaration {
  val name: Symbol
  val variableType: Type

  /**
   * Adds a binding to <code>ctx</code> from this variable to <code>value</code>. 
   * Evaluation of this variable under <code>ctx</code> will then result in <code>value</code>. 
   */
  def := (value: Any)(implicit ctx: MutableTypedMap[TypedKey, Any])
}

sealed trait UncheckedVariableExpr extends UncheckedExpression {
  def declaration: VariableDeclaration
  // Variables cannot be malformed 
  def checked(implicit ctx: MutableTypedMap[TypedKey, Any]): VariableExpr
}

object UncheckedVariableExpr {
  def apply(name: Symbol, variableType: Type): UncheckedVariableExpr =
    new VariableImpl(name, variableType)
}

sealed trait VariableExpr extends Expression {
  def declaration: VariableDeclaration
  /**
   * Short for <code>declaration.:=</code>.
   */
  def := (value: Any)(implicit ctx: MutableTypedMap[TypedKey, Any])
}

private class VariableImpl(val name: Symbol, val variableType: Type)
extends VariableDeclaration with VariableExpr with UncheckedVariableExpr {
  
  private val contextKey = TypedKey[Any](classOf[Any])
  
  override def declaration = this  
  override def childUncheckedExpressions = Seq.empty
  override def checked(implicit ctx: MutableTypedMap[TypedKey, Any]) = this

  override def childExpressions = Seq.empty
  override def expressionType(implicit ctx: MutableTypedMap[TypedKey, Any]) = variableType
  override def evaluate(implicit ctx: MutableTypedMap[TypedKey, Any]) = ctx(contextKey)
  override def :=(value: Any)(implicit ctx: MutableTypedMap[TypedKey, Any]) { ctx(contextKey) = value }

}
